package net.luohuasheng.bee.proxy.mybatis.executor.processor;

import net.luohuasheng.bee.jdbc.tools.common.utils.CollectionUtils;
import net.luohuasheng.bee.proxy.core.utils.jpa.JpaModelUtils;
import net.luohuasheng.bee.proxy.core.utils.jpa.dto.JpaColumnDto;
import net.luohuasheng.bee.proxy.core.utils.jpa.dto.JpaTableDto;
import net.luohuasheng.bee.proxy.jdbc.LoggingProxy;
import net.luohuasheng.bee.proxy.mybatis.executor.intercetor.WhereInterceptor;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.GenerationType;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author luohuasheng
 */
public abstract class BaseProcessor {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    protected final static String FOREACH_DEFAULT = "<foreach item=\"%s\" index=\"%s\" collection=\"%s\" open=\"%s\" separator=\"%s\" close=\"%s\">%s</foreach>";
    protected final static String BATCH_LIST = "list";
    protected final Configuration configuration;
    protected final Class<?> entityClass;
    private static final XMLLanguageDriver LANGUAGE_DRIVER = new XMLLanguageDriver();
    protected static final ThreadLocal<List<String>> UPDATE_EXPRESSION_FIELDS = new ThreadLocal<>();

    public static void setUpdateExpressionFields(String... fields) {
        UPDATE_EXPRESSION_FIELDS.set(Arrays.asList(fields));
    }


    public static List<String> getUpdateExpressionFields() {
        return UPDATE_EXPRESSION_FIELDS.get();
    }


    public static void remoteUpdateExpressionFields() {
        UPDATE_EXPRESSION_FIELDS.remove();
    }


    public JpaTableDto getJpaTableDto() {
        return jpaTableDto;
    }

    protected final JpaTableDto jpaTableDto;
    protected KeyGeneratorParameter generatorParameter;

    protected String addLogicConditions(List<JpaColumnDto> columns) {
        StringBuilder sb = new StringBuilder(WhereInterceptor.WHERE);
        if (CollectionUtils.isEmpty(columns)) {
            return sb.append(" 1=1 ").toString();
        } else {
            columns = columns.stream().filter(jpaColumnDto -> jpaColumnDto.getTableLogic() != null).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(columns)) {
                return sb.append(" 1=1 ").toString();
            } else {
                for (JpaColumnDto column : columns) {
                    if (WhereInterceptor.WHERE.equals(sb.toString())) {
                        if (org.apache.commons.lang3.StringUtils.isNumeric(column.getTableLogic().delFlag())) {
                            sb.append(" ").append(column.getName()).append("=").append(column.getTableLogic().noDelFlag()).append("");
                        } else {
                            sb.append(" ").append(column.getName()).append("='").append(column.getTableLogic().noDelFlag()).append("'");
                        }
                    } else {
                        if (org.apache.commons.lang3.StringUtils.isNumeric(column.getTableLogic().delFlag())) {
                            sb.append(" and ").append(column.getName()).append("=").append(column.getTableLogic().noDelFlag()).append("");
                        } else {
                            sb.append(" and ").append(column.getName()).append("='").append(column.getTableLogic().noDelFlag()).append("'");

                        }
                    }
                }
                return sb.insert(0, " ").toString();
            }
        }
    }


    public BaseProcessor(Configuration configuration, Class<?> entityClass) {
        this.configuration = configuration;
        this.entityClass = entityClass;
        jpaTableDto = JpaModelUtils.getJpaTable(entityClass);
    }

    protected KeyGeneratorParameter getKey() {
        if (generatorParameter == null) {
            generatorParameter = new KeyGeneratorParameter();
        }
        return generatorParameter;
    }

    protected SqlSource createSqlSource(String xmlSql) {
        return LANGUAGE_DRIVER.createSqlSource(configuration, "<script>\n\t" + xmlSql + "</script>", null);
    }

    public void rewrite(Invocation invocation, MappedStatement ms, BoundSql boundSql, Object parameter) throws Exception {

    }

    /**
     * 创建sql模块对象
     *
     * @return sql模块对象
     */
    public abstract SqlSource createSqlSource();

    public KeyGenerator keyGenerator() {
        return null;
    }

    public String keyProperty() {
        return null;

    }


    public String keyColumn() {
        return null;
    }

    protected String createPkSql(List<JpaColumnDto> columns) {
        StringBuilder sb = new StringBuilder();
        int i = 0;
        for (JpaColumnDto column : columns) {
            if (column.isPk()) {
                sb.append(" and ").append(column.getName()).append(" = #{pks[").append(i).append("]}");
                i++;
            }
        }
        return sb.toString();
    }

    /**
     * 主键参数内部类
     */
    class KeyGeneratorParameter {
        private KeyGenerator keyGenerator;
        private String keyProperty;
        private String keyColumn;

        KeyGeneratorParameter() {
            keyGenerator = new NoKeyGenerator();
            for (JpaColumnDto column : jpaTableDto.getColumns()) {
                keyProperty = column.getField().getName();
                keyColumn = column.getName();
                if (column.getStrategy() != null && column.getStrategy().equals(GenerationType.AUTO)) {
                    keyGenerator = new Jdbc3KeyGenerator();
                    break;
                }
            }

        }

        public KeyGenerator getKeyGenerator() {
            return keyGenerator;
        }

        public String getKeyProperty() {
            return keyProperty;
        }

        public void setKeyProperty(String keyProperty) {
            this.keyProperty = keyProperty;
        }

        public String getKeyColumn() {
            return keyColumn;
        }

        public void setKeyColumn(String keyColumn) {
            this.keyColumn = keyColumn;
        }
    }

    protected void callLog(MappedStatement ms) {
        LoggingProxy.addLogCall((text, input) -> {
            Logger logger = LoggerFactory.getLogger(ms.getId());
            LoggingProxy.localPrint(logger, text, input);
        });
    }
}
